<?php


namespace app\service\business;


use app\service\exception\BaseException;
use app\service\model\AttributeModel;
use app\service\model\CartModel;
use app\service\model\FreightModel;
use app\service\model\GoodsActivityModel;
use app\service\model\GoodsModel;
use app\service\model\GoodsSkuModel;
use app\service\model\MemberAddressModel;
use app\service\model\MemberCouponModel;
use app\service\model\OrderGoodsModel;
use app\service\model\OrderModel;
use app\service\model\VoucherModel;
use think\facade\Db;

class Order
{

    /**
     * 根据商品创建订单
     * @param $goods_id
     * @param $sku_id
     * @param $address_id
     * @param $member_id
     * @return OrderModel|\think\Model
     * @throws BaseException
     * @throws \app\service\exception\ApiException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function create_order_by_goods($goods_id, $sku_id, $address_id, $member_id, $appointment_time)
    {
        $num = (int)input('param.num', 1);
        if ($num < 1) {
            throw new BaseException(['msg' => '购买数量不能小于1']);
        }
        // 验证收货地址
        $address = self::checkAddress($address_id, $member_id);

        // 验证商品有效性、活动，返回商品信息
        $goods = self::checkGoods($goods_id, $sku_id);
        $goods['num'] = $num;
        $total = $goods_total_price = $goods['price'] * $num;

        $order_total_data = self::calcOrderTotal($member_id, $goods_total_price, $total, $address);

        // 创建订单
        return self::createOrder($member_id, $address, $order_total_data, [$goods], $appointment_time);
    }

    /**
     * 根据购物车创建订单
     * @param $cart_ids
     * @param $address_id
     * @param $member_id
     * @param $appointment_time
     * @return OrderModel|\think\Model
     * @throws BaseException
     * @throws \app\service\exception\ApiException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function create_order_by_cart($cart_ids, $address_id, $member_id, $appointment_time)
    {
        // 验证收货地址
        $address = self::checkAddress($address_id, $member_id);

        // 获取购物车列表
        $carts = CartModel::where('id', 'in', $cart_ids)->where('member_id', '=', $member_id)->select();
        $order_goods_list = [];
        $goods_total_price = 0;
        foreach ($carts as $cart) {
            // 验证商品有效性、活动，返回商品信息
            $goods = self::checkGoods($cart->goods_id, $cart->sku_id);
            $goods['num'] = $cart->num;
            $goods_total_price += $goods['price'] * $cart->num;
            $order_goods_list[] = $goods;
        }

        $total = $goods_total_price;

        $order_total_data = self::calcOrderTotal($member_id, $goods_total_price, $total, $address);

        // 创建订单
        return self::createOrder($member_id, $address, $order_total_data, $order_goods_list, $appointment_time);
    }

    /**
     * 检查收货地址
     * @param $address_id
     * @param $member_id
     * @return array|\think\Model
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function checkAddress($address_id, $member_id)
    {
        $address = MemberAddressModel::where('id', '=', $address_id)->where('member_id', '=', $member_id)->find();
        if (!$address) {
            throw new BaseException(['msg' => '收货地址不存在']);
        }
        return $address;
    }

    /**
     * 检查商品信息，并返回商品基本信息和活动优惠
     * @param $goods_id
     * @param $sku_id
     * @return array
     * @throws BaseException
     * @throws \app\service\exception\ApiException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function checkGoods($goods_id, $sku_id): array
    {
        $goods = GoodsModel::where('id', '=', $goods_id)->find();
        if (!$goods) {
            throw new BaseException(['msg' => '商品不存在']);
        }

        if ($goods->status != 1) {
            throw new BaseException(['msg' => '商品已下架']);
        }

        $return_data = [
            'goods_id' => $goods_id,
            'price' => $goods->price
        ];
        // 验证
        if ($goods->type == 2) {
            $sku = GoodsSkuModel::where('id', '=', $sku_id)->where('goods_id', '=', $goods_id)->find();
            if (!$sku) {
                throw new BaseException(['msg' => '商品不存在']);
            }
            $return_data['price'] = $sku->price;
            $return_data['attribute'] = implode(' ', AttributeModel::where('id', 'in', $sku->attrs)->column('name'));
        }

        $activity = GoodsActivityModel::getActivity($goods_id);
        if ($activity) {
            $return_data['price'] = $return_data['price'] * ($activity->discount / 10);
            $return_data['activity_id'] = $activity->id;
            $return_data['activity_info'] = $activity->name . '-' . $activity->discount . '折';
        }

        return $return_data;
    }

    /**
     * 优惠券信息
     * @param $member_id
     * @param $goods_total_price
     * @param int $coupon_id
     * @param int $coupon_money
     * @return bool
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getCouponInfo($member_id, $goods_total_price, &$coupon_id = 0, &$coupon_money = 0): bool
    {
        $coupon_id = input('param.coupon_id', 0);
        if (!$coupon_id) {
            return false;
        }
        $member_coupon = MemberCouponModel::hasWhere('coupon', function ($query) {
            $query->where(function ($query) {
                $time = date('Y-m-d H:i:s');
                $query->where('start_time', '<', $time)->where('end_time', '>', $time);
            })->whereOr('is_permanent_validity', '=', 1);
        })->where('MemberCouponModel.id', '=', $coupon_id)
            ->where('member_id', '=', $member_id)
            ->where('status', '=', 1)
            ->find();
        if (!$member_coupon) {
            throw new BaseException(['msg' => '优惠券不可用']);
        }
        if ($member_coupon->coupon->restrict > 0 && $member_coupon->coupon->restrict > $goods_total_price ) {
            throw new BaseException(['msg' => '商品金额必须大于' . $member_coupon->coupon->restrict . '，才可以使用该优惠券']);
        }
        $coupon_money = $member_coupon->coupon->money;

        $member_coupon->save(['status' => 2]);

        return true;
    }

    /**
     * 抵扣券信息
     * @param $member_id
     * @param int $voucher_id
     * @param int $voucher_money
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getVoucher($member_id, &$voucher_id = 0, &$voucher_money = 0): bool
    {
        $voucher = VoucherModel::where('member_id', '=', $member_id)->where('status', '=', 1)->find();
        if (!$voucher) {
            return false;
        }
        $order = OrderModel::field('id')->where('voucher_id', '=', $voucher->id)->find();
        if ($order) {
            return false;
        }
        $voucher_id = $voucher->id;
        $voucher_money = $voucher->money;
        $voucher->save(['status' => 2]);
        return true;
    }

    /**
     * 创建订单
     * @param $member_id
     * @param $address
     * @param $order_total_data
     * @param $goods_list
     * @return OrderModel|\think\Model
     * @throws BaseException
     */
    public static function createOrder($member_id, $address, $order_total_data, $goods_list, $appointment_time)
    {
        extract($order_total_data);
        /**
         * @var float $total
         * @var float $unpaid
         * @var int $coupon_id
         * @var float $coupon_money
         * @var int $voucher_id
         * @var float $voucher_money
         * @var float $freight
         * @var float $goods_price
         */
        Db::startTrans();
        try {
            $order_no = makeOrderNo('D');
            $order = OrderModel::create([
                'member_id' => $member_id,
                'order_no' => $order_no,
                'total' => $total,
                'unpaid' => $unpaid,
                'goods_price' => $goods_price,
                'member_coupon_id' => $coupon_id,
                'coupon_money' => $coupon_money,
                'voucher_id' => $voucher_id,
                'voucher_money' => $voucher_money,
                'consignee' => $address->consignee,
                'mobile' => $address->mobile,
                'address' => $address->loc_name . $address->address,
                'distance' => $address->distance,
                'freight' => $freight,
                'appointment_time' => $appointment_time,
                'remark' => input('param.remark', '')
            ]);

            // 保存订单商品
            foreach ($goods_list as &$goods) {
                $goods['order_id'] = $order->id;
            }
            OrderGoodsModel::insertAll($goods_list);
            Db::commit();
            return $order;
        } catch (\Exception $e) {
            Db::rollback();
            trace($e->getMessage() . "\n" . $e->getFile() . "\n" . $e->getCode(), '下单失败');
            throw new BaseException(['msg' => '下单失败']);
        }
    }

    /**
     * 计算订单总额
     * @param $member_id
     * @param $goods_total_price
     * @param $total
     * @param $address
     * @return array
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function calcOrderTotal($member_id, $goods_total_price, $total, $address): array
    {
        $coupon_id = $voucher_id = $coupon_money = $voucher_money = 0;
        $goods_price = $goods_total_price;
        // 验证优惠券
        self::getCouponInfo($member_id, $goods_total_price, $coupon_id,$coupon_money);

        // 验证抵扣券
        self::getVoucher($member_id, $voucher_id, $voucher_money);

        // 商品最终金额
        $goods_total_price = $goods_total_price - $coupon_money - $voucher_money;
        $goods_total_price = $goods_total_price > 0 ? $goods_total_price : 0;

        // 计算运费
        $total += $freight = FreightModel::calcFreight($address->distance);

        // 订单实付金额
        $unpaid = $goods_total_price + $freight;
        return compact('total', 'unpaid', 'coupon_id', 'coupon_money', 'voucher_id', 'voucher_money', 'freight', 'goods_price');
    }
}